package com.example.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.example.common.Result;
import com.example.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Component
public class AuthFilter extends AbstractGatewayFilterFactory<AuthFilter.Config> {

    @Autowired
    private JwtUtil jwtUtil;

    public AuthFilter() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            ServerHttpResponse response = exchange.getResponse();

            String path = request.getURI().getPath();
            log.info("请求路径: {}", path);

            // 检查是否为排除路径
            if (isExcludePath(path, config.getExcludePaths())) {
                log.info("排除路径，直接放行: {}", path);
                return chain.filter(exchange);
            }

            // 获取Authorization头
            String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
            if (StrUtil.isBlank(authHeader)) {
                log.warn("缺少Authorization头");
                return unauthorizedResponse(response, "缺少认证信息");
            }

            // 提取token
            String token = jwtUtil.extractTokenFromHeader(authHeader);
            if (StrUtil.isBlank(token)) {
                log.warn("无效的Authorization头格式: {}", authHeader);
                return unauthorizedResponse(response, "无效的认证信息格式");
            }

            // 本地验证token格式
//            if (!jwtUtil.validateToken(token)) {
//                log.warn("Token验证失败: {}", token);
//                return unauthorizedResponse(response, "无效的认证信息");
//            }

            // 检查token是否过期
            if (jwtUtil.isTokenExpired(token)) {
                log.warn("Token已过期: {}", token);
                return unauthorizedResponse(response, "认证信息已过期");
            }

            // 从token中解析用户信息
            try {
                Long userId = jwtUtil.getUserIdFromToken(token);
                String username = jwtUtil.getUsernameFromToken(token);

                if (userId == null || username == null) {
                    log.warn("无法从token中获取用户信息: userId={}, username={}", userId, username);
                    return unauthorizedResponse(response, "无法获取用户信息");
                }

                // 将用户信息添加到请求头中，供下游服务使用
                ServerHttpRequest modifiedRequest = request.mutate()
                        .header("X-User-Id", userId.toString())
                        .header("X-Username", username)
                        .build();

                log.info("用户认证成功: userId={}, username={}", userId, username);

                return chain.filter(exchange.mutate().request(modifiedRequest).build());

            } catch (Exception e) {
                log.error("解析token时发生异常", e);
                return unauthorizedResponse(response, "token解析失败");
            }
        };
    }

    /**
     * 检查是否为排除路径
     */
    private boolean isExcludePath(String path, String excludePaths) {
        if (StrUtil.isBlank(excludePaths)) {
            return false;
        }

        List<String> excludeList = Arrays.asList(excludePaths.split(","));
        return excludeList.stream().anyMatch(excludePath -> path.endsWith(excludePath.trim()));
    }

    /**
     * 返回未授权响应
     */
    private Mono<Void> unauthorizedResponse(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

        Result<String> result = Result.error(401, message);
        String body = JSONUtil.toJsonStr(result);
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }

    public static class Config {
        private String excludePaths;

        public String getExcludePaths() {
            return excludePaths;
        }

        public void setExcludePaths(String excludePaths) {
            this.excludePaths = excludePaths;
        }
    }
}
